Serverless Frameworkでリトライの調整ができる定期実行なLambda関数を作成する
データアナリティクス事業本部の鈴木です。
Serverless Frameworkからスケジュール実行されるStep Functionsのステートマシンと、ステートマシンから呼び出されるLambda関数を作成することで、「定期的に実行され、失敗時には指定時間後にリトライされるLambda関数」を作ってみました。
やりたいこと
以前、『Lambdaをスケジュール実行して関数エラーが起きた際の再試行を確認してみた | DevelopersIO』でAmazon EventBridgeからスケジュール実行されるLambda関数についてご紹介しました。EventBridgeからの非同期呼び出しで関数エラーが起きた場合には、0〜2の設定した回数と、決められた数分程度の間隔でリトライが行われます。
もっとたくさんの回数や、長い間隔でリトライしたい場合は、別の方法を考える必要があります。
今回は、Step FunctionsのステートマシンがEventBridgeから呼び出せることに注目し、以下のような構成を試してみました。
データ基盤でのユースケースだと、複数のある程度時間がかかる取り込み処理が稼働しており、どれも動いていないときにLambda関数で簡単なチェック処理を行うような場合を想定しています。後に記載しているLambda関数の実装は、このケースを念頭に作成しています。
ツールの準備
今回はServerless Frameworkを使ってリソースを作成しました。
バージョンなどは以下になります。
- Serverless Framework
serverless --version # Framework Core: 2.43.1 (standalone) # Plugin: 5.1.3 # SDK: 4.2.2 # Components: 3.10.0
- Serverless Step Functionsプラグイン:3.5.1
やってみる
プロジェクトを作成する
まず、テンプレートを生成します。
※ 手順はServerless Frameworkで構築するStep Functions | DevelopersIOを参考にしました。
# プロジェクトを作成する。 serverless create --template aws-python3 --name StepFunctionsService --path TestStepFunctions
TestStepFunctionsディレクトリ配下は以下のようになっています。
tree -L 1 # . # ├── handler.py # └── serverless.yml
Step Functionsを利用するために、Serverless Step Functionsプラグインをインストールします。
# Serverless Step Functionsプラグインをインストールする。 cd TestStepFunctions/ npm install --save-dev serverless-step-functions
Lambda関数の修正
ステートマシンから起動するLambda関数を作成するため、handler.py
を修正します。
今回は以下のようなコードを用意しました。
import json class NotCompletedException(Exception): pass def lambda_handler(event, context): print("処理がまだ終わっていませんでした。例外を送出します。") raise NotCompletedException return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') }
lambda_handler
関数では、3行目で定義しているNotCompletedException
をとりあえず送出するようになっています。実際は前提となる処理が終わっているか確認して、まだ終わっていない場合はこの例外を送出するイメージです。
serverless.ymlの修正
サービス全体の設定を行うためのファイルであるserverless.yml
を修正します。
スケジュール起動するステートマシンを作るため、以下のドキュメントを参考に修正しました。
完成したserverless.yml
はこちらです。
service: cm-nayuts-StepFunctionsService frameworkVersion: '2' plugins: - serverless-step-functions provider: name: aws runtime: python3.8 region: ap-northeast-1 functions: CMNayutsSampleFunction: handler: handler.lambda_handler stepFunctions: stateMachines: CMNayutsSampleStateMachine: name: cm-nayuts-sample-StateMachine events: - schedule: cron(40 5 * * ? *) definition: StartAt: SampleInvocation States: SampleInvocation: Type: Task Resource: Fn::GetAtt: [CMNayutsSampleFunction, Arn] Retry: - ErrorEquals: - "NotCompletedException" IntervalSeconds: 5 MaxAttempts: 3 BackoffRate: 2 End: true
ポイントはハイライトした箇所です。
まず、events
でスケジュール起動を設定しました。
また、Retry
にてLambda関数でNotCompletedException
(Lambda関数内で定義した自作の例外)が投げられた場合には、2回までリトライするようにしています。
※ Lambdaの関数の例外をステートマシンで受け取る方法は、以下のチュートリアルを参考にしました。
デプロイする
準備ができたので、リソースをデプロイします。
# デプロイする sls deploy -v
CFnスタックが作成され、serverless.yml
で定義したリソースがデプロイされます。
起動を確認する
スケジュール起動を設定しているので、起動時間後に挙動を確認します。
Lambda関数で例外を送出しているので、ステータスは失敗になっています。
実行イベント履歴を確認すると、指定通り2回リトライされています。待ち時間はIntervalSeconds
が5秒で、BackoffRate
が2なので、指定通りの5秒と10秒になっていることが確認できます。
Lambdaのログを見ると、実装通りエラーが送出されていることが確認できました。
最後に
Serverless Frameworkからスケジュール実行されるStep Functionsのステートマシンと、ステートマシンから呼び出されるLambda関数を作成する方法を紹介しました。
試してみるまでは難しいイメージがありましたが、Serverless Frameworkを使うと手軽にLambdaとほかのサービスを組み合わせた仕組みがデプロイできるので良いですね。